package gate

import (
	"base"
	"emma/protobuf"
	"emma/service"
	"fmt"
	"github.com/golang/protobuf/proto"
	"proto/base"
	"proto/player"
	"reflect"
	"strings"
	gate_response "test_client/logic/gate/response"
	. "test_client/logic/internal"
	"test_client/logic/player/event"
	"time"
)

type gateService struct {
}

func init() {
	service := new(gateService)

	Proto.Register(new(proto_player.OnLogin), service.onLogin)
	Proto.Register(new(proto_player.OnLogout), service.onLogout)
	Proto.Register(new(proto_player.Response), service.response)
}

func (*gateService) onLogin(args []interface{}) {
	msg := args[0].(*proto_player.OnLogin)
	code := msg.Code
	if code != proto_base.ErrorCode_Success {
		base.Logger.Release("玩家登录失败, code: %s", code)
		return
	}

	base.Logger.Release("玩家登录成功, %s", msg.PlayerId)

	Event.Notify(player_event.OnLogin)
}

func (*gateService) onLogout(args []interface{}) {
	base.Logger.Release("remove player")
}

func (*gateService) response(args []interface{}) {
	response := args[0].(*proto_player.Response)
	protoName := response.Name
	method, exists := Service.Get(protoName)
	if !exists {
		base.Logger.Warning("not %s service.method", protoName)
		return
	}

	parseArgs := func(response *proto_player.Response, method *service.Method) (result []reflect.Value, err error) {
		result = make([]reflect.Value, 0, 2)
		paramsCount := method.ParamsCount()
		i := 1

		if paramsCount >= i {
			i++
			protoMsg, exists := protobuf.New(response.Name)
			if !exists {
				err = fmt.Errorf("undefined %s message", response.Name)
				return
			}
			if err = proto.Unmarshal(response.Data, protoMsg); err != nil {
				return
			}
			result = append(result, reflect.ValueOf(protoMsg))
			base.Logger.Debug("proto message: %s", protoMsg)
		}

		if paramsCount >= i {
			i++
			args := new(gate_response.Args)
			args.ErrorCode = response.Code
			args.ErrorArgs = response.Args
			result = append(result, reflect.ValueOf(args))
		}

		return
	}

	handle := func(response *proto_player.Response, method *service.Method) error {
		base.Logger.Release("handle gate response %s begin.", response.Name)
		if response.Code != proto_base.ErrorCode_Success {
			base.Logger.Error("code: %s, args: %s", response.Code, strings.Join(response.Args, ", "))
		}

		args, err := parseArgs(response, method)
		if err != nil {
			return err
		}

		defer func(start time.Time) {
			if r := recover(); r != nil {
				base.Logger.Error("handle gate response %s error, reason: %v", response.Name, r)
			} else {
				base.Logger.Release("handle gate response %s end, cost time %v", response.Name, time.Since(start))
			}
		}(time.Now())

		return method.Call(args)
	}

	handle(response, method)
}
